#include "stdafx.h"
#include "CConsole.h"
#include "CParser.h"
#include "CAssembler.h"

COperand	CAssembler::s_pOperands[];
int			CAssembler::s_nOperandIndex;

const sMnemonicTableEntry MnemonicTable[NUM_MNEMONICS] =
{
	{"AAA", AAA},		{"AAD", AAD},		{"AAM", AAM},		{"AAS", AAS},		{"ADC", ADC},
	{"ADD", ADD},		{"AND", AND},		{"ARPL", ARPL},
	{"BOUND", BOUND},	{"BSF", BSF},		{"BSR", BSR},		{"BSWAP", BSWAP},	{"BT", BT},
	{"BTC", BTC},		{"BTR", BTR},		{"BTS", BTS},
	{"CALL", CALL},		{"CBW", CBW},		{"CDQ", CDQ},		{"CLC", CLC},		{"CLD", CLD},
	{"CLI", CLI},		{"CLTS", CLTS},		{"CMC", CMC},		{"CMP", CMP},		{"CMPS", CMPS},
	{"CMPXCHG", CMPXCHG},{"CWD", CWD},		{"CWDE", CWDE},
	{"DAA", DAA},		{"DAS", DAS},		{"DEC", DEC},		{"DIV", DIV},		{"ENTER", ENTER},
	{"ESC", ESC},
	//FLOATING_POINT_INSTRUCTION,
	{"HLT", HLT},
	{"IDIV", IDIV},		{"IMUL", IMUL},		{"INC", INC},		{"INS", INS},		{"INT", mINT},
	{"INT1", INT1},		{"INT3", INT3},		{"INTO", INTO},		{"INVD", INVD},		{"INVLPG", INVLPG},
	{"IRET", IRET},
	{"JA", JA},			{"JAE", JAE},		{"JB", JB},			{"JBE", JBE},		{"JC", JC},
	{"JCXZ", JCXZ},		{"JE", JE},			{"JG", JG},			{"JGE", JGE},		{"JL", JL},
	{"JLE", JLE},		{"JMP", JMP},		{"JNC", JNC},		{"JNE", JNE},		{"JNO", JNO},
	{"JNS", JNS},		{"JNP", JNP},		{"JO", JO},			{"JP", JP},			{"JS", JS},
	{"LAHF", LAHF},		{"LAR", LAR},		{"LDS", LDS},		{"LEA", LEA},		{"LEAVE", LEAVE},
	{"LES", LES},		{"LFS", LFS},		{"LGDT", LGDT},		{"LIDT", LIDT},		{"LGS", LGS},
	{"LLDT", LLDT},		{"LMSW", LMSW},		{"LOCK", LOCK},		{"LODS", LODS},		{"LOOP", LOOP},
	{"LOOPE", LOOPE},	{"LOOPNZ", LOOPNZ},	{"LSL", LSL},		{"LSS", LSS},		{"LTR", LTR},
	{"MOV", MOV},		{"MOVS", MOVS},		{"MOVSX", MOVSX},	{"MOVZX", MOVZX},	{"MUL", MUL},
	{"NEG", NEG},		{"NOP", NOP},		{"NOT", NOT},
	{"OR", OR},			{"OUTS", OUTS},
	{"POP", POP},		{"POPA", POPA},		{"POPAD", POPAD},	{"POPF", POPF},		{"POPFD", POPFD},
	{"PUSH", PUSH},		{"PUSHA", PUSHA},	{"PUSHAD", PUSHA},	{"PUSHF", PUSHF},
	{"RCL", RCL},		{"RCR", RCR},		{"REP", REP},		{"REPE", REPE},		{"REPNE", REPNE},
	{"RET", RET},		{"ROL", ROL},		{"ROR", ROR},
	{"SAHF", SAHF},		{"SAL", SAL},		{"SALC", SALC},		{"SAR", SAR},		{"SBB", SBB},
	{"SCAS", SCAS},		{"SETAE", SETAE},	{"SETB", SETB},		{"SETBE", SETBE},	{"SETE", SETE},
	{"SETNE", SETNE},	{"SETL", SETL},		{"SETGE", SETGE},	{"SETLE", SETLE},	{"SETG", SETG},
	{"SETS", SETS},		{"SETNS", SETNS},	{"SETC", SETC},		{"SETNC", SETNC},	{"SETO", SETO},
	{"SETNO", SETNO},	{"SETP", SETP},		{"SETNP", SETNP},	{"SGDT", SGDT},		{"SIDT", SIDT},
	{"SHR", SHR},		{"SHLD", SHLD},		{"SLDT", SLDT},		{"SMSW", SMSW},		{"STC", STC},
	{"STD", STD},		{"STI", STI},		{"STOS", STOS},		{"STR", STR},		{"SUB", SUB},
	{"TEST", TEST},
	{"VERR", VERR},		{"VERW", VERW},
	{"WAIT", WAIT},		{"WBINVD", WBINVD},
	{"XCHG", XCHG},		{"XLAT", XLAT},		{"XOR", XOR},
};

const sRegisterTableEntry RegisterTable[NUM_REGISTERS] =
{
	{"AL", AL},		{"CL", CL},		{"DL", DL},		{"BL", BL},
	{"AH", AH},		{"CH", CH},		{"DH", DH},		{"BH", BH},
	{"AX", AX},		{"CX", CX},		{"DX", DX},		{"BX", BX},
	{"SP", SP},		{"BP", BP},		{"SI", SI},		{"DI", DI},
	{"EAX", EAX},	{"ECX", ECX},	{"EDX", EDX},	{"EBX", EBX},
	{"ESP", ESP},	{"EBP", EBP},	{"ESI", ESI},	{"EDI", EDI},
};

const sSegment SegmentTable[NUM_SEGMENTS] =
{
	{"DS", DS},		{"ES", ES},		{"FS", FS},		{"GS", GS},
	{"SS", SS},		{"CS", CS},		{"IP", IP}
};

#define MNEMONIC(a,...) {a,{__VA_ARGS__}}
#define OPCODE(a,b,...) {true,OPCODE_##a,0,b,{__VA_ARGS__}}
#define EXOPCODE(a,b,...) {true,0xF,EXOPCODE_##a,b,{__VA_ARGS__}}
#define OPERAND(a,b) {true,(eOperandType)OPERAND_##a,b}
#define NULL_OPERAND {false,BAD_OPERAND,0}

/*sInstructionDefinition OpcodeDefinitionTable[NUM_MNEMONICS] = {
	MNEMONIC(ADD,
		OPCODE(ADD_AL_IB, 2, OPERAND(REGISTER_AX, 1),	OPERAND(VALUE8, 1)),
		OPCODE(ADD_AX_IV, 2, OPERAND(REGISTER_AX, 4),	OPERAND(VALUE32, 4)),
		OPCODE(ADD_EB_GB, 1, OPERAND(EXTENDED_BYTE, 1),	OPERAND(GENERAL_BYTE, 1)),
		OPCODE(ADD_EV_GV, 1, OPERAND(EXTENDED_VAL, 4),	OPERAND(GENERAL_VAL, 4)),
		OPCODE(ADD_GB_EB, 1, OPERAND(GENERAL_BYTE, 1),	OPERAND(EXTENDED_BYTE, 1)),
		OPCODE(ADD_GV_EV, 1, OPERAND(GENERAL_VAL, 4),	OPERAND(EXTENDED_VAL, 4)),
		OPCODE(ADD_EB_IB, 2, OPERAND(EXTENDED_BYTE, 1),	OPERAND(VALUE8, 1)),
		OPCODE(ADD_EV_IV, 2, OPERAND(EXTENDED_VAL, 4),	OPERAND(VALUE32, 4)),
	),
	MNEMONIC(INC,
		OPCODE(INC_AX, 0, OPERAND(REGISTER_AX, 4)),
		OPCODE(INC_CX, 0, OPERAND(REGISTER_CX, 4)),
		OPCODE(INC_DX, 0, OPERAND(REGISTER_DX, 4)),
		OPCODE(INC_BX, 0, OPERAND(REGISTER_BX, 4)),
		OPCODE(INC_SP, 0, OPERAND(REGISTER_SP, 4)),
		OPCODE(INC_BP, 0, OPERAND(REGISTER_BP, 4)),
		OPCODE(INC_SI, 0, OPERAND(REGISTER_SI, 4)),
		OPCODE(INC_DI, 0, OPERAND(REGISTER_DI, 4))
	),
	MNEMONIC(DEC,
		OPCODE(DEC_AX, 0, OPERAND(REGISTER_AX, 4)),
		OPCODE(DEC_CX, 0, OPERAND(REGISTER_CX, 4)),
		OPCODE(DEC_DX, 0, OPERAND(REGISTER_DX, 4)),
		OPCODE(DEC_BX, 0, OPERAND(REGISTER_BX, 4)),
		OPCODE(DEC_SP, 0, OPERAND(REGISTER_SP, 4)),
		OPCODE(DEC_BP, 0, OPERAND(REGISTER_BP, 4)),
		OPCODE(DEC_SI, 0, OPERAND(REGISTER_SI, 4)),
		OPCODE(DEC_DI, 0, OPERAND(REGISTER_DI, 4))
	),
	MNEMONIC(PUSH,
		OPCODE(PUSH, 0, OPERAND(NOMODREGRM, 4)),
		OPCODE(PUSH_IMM8, 1, OPERAND(VALUE8, 1)),
		OPCODE(PUSH_IMM32, 1, OPERAND(VALUE32, 1))
	),
	MNEMONIC(POP,
		OPCODE(POP, 0, OPERAND(NOMODREGRM, 4))
	),
};*/

int CAssembler::AssembleLine(CToken ** pTokens)
{
	CToken * tokens[MAX_TOKENS];
	int size = 0;
	int num_tokens = 0;
	eRegister regs[2];
	eSegment seg;
	eMnemonicInstruction instruction;

	bool bDisplaceOpen = false;

	for(num_tokens=0; num_tokens < GetNumRegisteredTokens(); num_tokens++)
	{
		tokens[num_tokens] = RecallToken(num_tokens);
		tokens[num_tokens+1] = nullptr;

		if(tokens[num_tokens]->GetType() == TOKEN_STRING)
		{
			if((regs[0] = GetRegister(tokens[num_tokens]->GetString())) != BAD_REGISTER)
			{
				s_pOperands[num_tokens].SetType(ASM_REGISTER);
				s_pOperands[num_tokens].SetValue(regs[0]);
			}
			else if((seg = GetSegment(tokens[num_tokens]->GetString())) != BAD_SEGMENT)
			{
				s_pOperands[num_tokens].SetType(ASM_SEGMENT);
				s_pOperands[num_tokens].SetValue(seg);
			}
			else if((instruction = GetInstruction(tokens[num_tokens]->GetString())) != BAD_INSTRUCTION)
			{
				s_pOperands[num_tokens].SetType(ASM_INSTRUCTION);
				s_pOperands[num_tokens].SetValue(instruction);
			}
			else THROW("Unknown operand '%s'", tokens[num_tokens]->GetString());
		}
		else if(tokens[num_tokens]->GetType() == TOKEN_VALUE)
		{
			s_pOperands[num_tokens].SetType(ASM_VALUE);
			s_pOperands[num_tokens].SetValue(tokens[num_tokens]->GetIntValue());
		}
		else if(tokens[num_tokens]->GetType() == TOKEN_ASM_DISPLACE)
		{
			bDisplaceOpen = true;
		}
		else if(tokens[num_tokens]->GetType() == TOKEN_ASM_DISPLACE_END)
		{
			if(!bDisplaceOpen) throw("Unmatched bracket ']'");
			bDisplaceOpen = false;
		}
		else throw("Unknown token");
		
		SetToken(num_tokens, nullptr);
	}

	if(bDisplaceOpen) throw("Unmatched bracket '['");

	RewindLine();

	if(tokens[0])
	{
		while(true)
		{
			switch(s_pOperands[0].GetInstruction())
			{
			case ADD:
				bDisplaceOpen = CollectIsDisplace();

				regs[0] = CollectRegister();
				if(regs[0] == EAX)
				{
					if(GetOperandType() == ASM_REGISTER)
					{
						regs[1] = CollectRegister();
					}
					else
					{
						// oh screw it...
					}
				}
				break;
			default:
				throw("Unhandled instruction");
			}
		}
		
#if FALSE
#define CASE_OPCODE(a,b,c,...) case a: opcode = b;\
	num_operands = c;\
	break;

		switch(instruction)
		{
		CASE_OPCODE(AAA,	OPCODE_AAA,				2)
		CASE_OPCODE(AAS,	OPCODE_AAS,				0)
		CASE_OPCODE(ADD,	UNIDENTIFIED_OPCODE,	2)
		CASE_OPCODE(CBW,	OPCODE_CBW,				0)
		CASE_OPCODE(CLC,	OPCODE_CLC,				0)
		CASE_OPCODE(CLD,	OPCODE_CLD,				0)
		CASE_OPCODE(CLI,	OPCODE_CLI,				0)
		CASE_OPCODE(CMC,	OPCODE_CMC,				0)
		CASE_OPCODE(CWD,	OPCODE_CWD,				0)
		CASE_OPCODE(DAA,	OPCODE_DAA,				0)
		CASE_OPCODE(DAS,	OPCODE_DAS,				0)
		CASE_OPCODE(DEC,	UNIDENTIFIED_OPCODE,	0)
		CASE_OPCODE(HLT,	OPCODE_HLT,				0)
		CASE_OPCODE(INC,	UNIDENTIFIED_OPCODE,	0)
		CASE_OPCODE(INT1,	OPCODE_INT1,			0)
		CASE_OPCODE(INT3,	OPCODE_INT3,			0)
		CASE_OPCODE(INTO,	OPCODE_INTO,			0)
		CASE_OPCODE(IRET,	OPCODE_IRET,			0)
		CASE_OPCODE(LAHF,	OPCODE_LAHF,			0)
		CASE_OPCODE(LEAVE,	OPCODE_LEAVE,			0)
		CASE_OPCODE(NOP,	OPCODE_NOP,				0)
		CASE_OPCODE(MOV,	UNIDENTIFIED_OPCODE,	2)
		CASE_OPCODE(POP,	UNIDENTIFIED_OPCODE,	1)
		CASE_OPCODE(POPA,	OPCODE_POPA,			0)
		CASE_OPCODE(PUSH,	UNIDENTIFIED_OPCODE,	1)
		CASE_OPCODE(PUSHA,	OPCODE_PUSHA,			0)
		CASE_OPCODE(SAHF,	OPCODE_SAHF,			0)
		CASE_OPCODE(SALC,	OPCODE_SALC,			0)
		CASE_OPCODE(STC,	OPCODE_STC,				0)
		CASE_OPCODE(STD,	OPCODE_STD,				0)
		CASE_OPCODE(STI,	OPCODE_STI,				0)
		CASE_OPCODE(XLAT,	OPCODE_XLAT,			0)
		CASE_OPCODE(WAIT,	OPCODE_WAIT,			0)
		default: THROW("Unhandled instruction '%s'", tokens[0]->GetString());
		}

		CToken * pToken;

		if(num_operands)
		{
			int i;
			eOperandType types[5] = {BAD_OPERAND,BAD_OPERAND,BAD_OPERAND,BAD_OPERAND,BAD_OPERAND};
			eRegister regs[5] = {BAD_REGISTER,BAD_REGISTER,BAD_REGISTER,BAD_REGISTER,BAD_REGISTER};
			eSegment segs[5] = {BAD_SEGMENT,BAD_SEGMENT,BAD_SEGMENT,BAD_SEGMENT,BAD_SEGMENT};
			sInstructionDefinition * pInstruction = GetInstructionDefinition(instruction);

			for(i=0; num_operands--; i++)
			{
				CToken *token = tokens[i+1];
				switch(token->GetType())
				{
				case TOKEN_VALUE:
					switch(GetIntNumBytes(token->GetIntValue()))
					{
					case 1: types[i] = OPERAND_VALUE8;
						break;
					case 2: types[i] = OPERAND_VALUE16;
						break;
					default: types[i] = OPERAND_VALUE32;
						break;
					}
					break;
				default:
					if((reg = GetRegister(token)) != BAD_REGISTER)
					{
						if((types[i] = GetRegisterOperandType(reg)) == BAD_OPERAND)
							THROW("Unhandled register '%s'", token->GetString());
						
						regs[i] = reg;
					}
					else if((seg = GetSegment(token)) != BAD_SEGMENT)
					{
						switch(seg)
						{
						case DS: types[i] = OPERAND_SEGMENT_DS; break;
						case ES: types[i] = OPERAND_SEGMENT_ES; break;
						case FS: types[i] = OPERAND_SEGMENT_FS; break;
						case GS: types[i] = OPERAND_SEGMENT_GS; break;
						case SS: types[i] = OPERAND_SEGMENT_SS; break;
						case CS: types[i] = OPERAND_SEGMENT_CS; break;
						}

						segs[i] = seg;
					}
					else throw("Expected operand");
					break;
				}
			}

			sOperand * pOperand;
			sOpcodeDefinition * opcodeDefinition;
			
			for(int j=0; j < 16; j++)
			{
				opcodeDefinition = &pInstruction->opcodes[j];
				pOperand = nullptr;
				if(!opcodeDefinition->used)
					break;

				int n = 0;
				while(n < i)
				{
					pOperand = &opcodeDefinition->operands[n];
					if(!pOperand->used)
					{
						pOperand = nullptr;
						break;
					}
					if(!AreOperandsCompatible(pOperand->type, types[n]))
					{
						eOperandType type = ConvertRegisterToOperand(regs[n]);
						if(
							regs[n] == BAD_REGISTER ||
							(pOperand->type != type && pOperand->type != OPERAND_NOMODREGRM)
						) break;
					}
					else if(regs[n] != BAD_REGISTER)
					{
						if(pOperand->type >= OPERAND_REGISTER_AX && pOperand->type <= OPERAND_REGISTER_DI)
						{
							if(GetRegisterOperandType(regs[n]) != pOperand->type)
								break;
						}
						else if(GetRegisterDataSize(regs[n]) != pOperand->size) break;
					}
					n++;
				}

				if(n == i) break;
			}

			if(!opcodeDefinition->used)
				throw("Operands incompatible with command");
			if(types[i-1] == BAD_OPERAND) throw("Bad operand");

			int n = 0;
			BYTE opcode = opcodeDefinition->opcode;

			if(pOperand)
			{
				switch(pOperand->type)
				{
				case OPERAND_REGISTER_AX:
				case OPERAND_REGISTER_CX:
				case OPERAND_REGISTER_DX:
				case OPERAND_REGISTER_BX:
				case OPERAND_REGISTER_SP:
				case OPERAND_REGISTER_BP:
				case OPERAND_REGISTER_SI:
				case OPERAND_REGISTER_DI:
					if(regs[n] == BAD_REGISTER) throw("Expected register");
					if(GetRegisterOperandType(regs[n]) != pOperand->type)
						throw("Incorrect register");
					n++;
					break;
				case OPERAND_NOMODREGRM:
					// Turn "MOV" into "MOV EAX...", "ADD" to "ADD AL...", etc.
					if(regs[n] == BAD_REGISTER) throw("Expected register");
					opcode |= GetRegisterID(regs[n++]);
					break;
				}
			}

			// Commit the opcode
			pToken = RegisterToken(TOKEN_HEX_BYTE, tokens[0]->GetString());
			pToken->SetValue(opcode);
			pToken->Trace();
			size += pToken->GetSize();

			for(int j=0; j < opcodeDefinition->num_operands; j++)
			{
				CToken * token = tokens[n+1];
				sOperand * operand = &opcodeDefinition->operands[n],
						 * operandTemp;
				eTokenType ttype = TOKEN_NONE;
				sModRegRm modRegRm;
				eRegister set_reg = BAD_REGISTER;
				pToken = nullptr;
				reg = regs[n];
				
				switch(operand->type)
				{
				case OPERAND_VALUE32:
					if(types[n] < OPERAND_VALUE8 || types[n] > OPERAND_VALUE32)
						throw("Expected value");
					ttype = TOKEN_HEX_DWORD;
				case OPERAND_VALUE16:
					if(!ttype)
					{
						if(types[n] < OPERAND_VALUE8 || types[n] > OPERAND_VALUE32)
							throw("Expected value");
						if(types[n] > OPERAND_VALUE16)
							throw("Value too high for 16 bit");
						ttype = TOKEN_HEX_WORD;
					}
				case OPERAND_VALUE8:
					if(!ttype)
					{
						if(types[n] < OPERAND_VALUE8 || types[n] > OPERAND_VALUE32)
							throw("Expected value");
						if(types[n] > OPERAND_VALUE8)
							throw("Value too high for 8 bit");
						ttype = TOKEN_HEX_BYTE;
					}
					pToken = RegisterToken(ttype, token->GetString());
					pToken->SetValue(token->GetIntValue());
					pToken->SetValueType(PT_INT);
					break;
				case OPERAND_REGISTER_AX:
					if(set_reg == BAD_REGISTER) set_reg = pOperand->size == 4 ? EAX : AL;
				case OPERAND_REGISTER_CX:
					if(set_reg == BAD_REGISTER) set_reg = pOperand->size == 4 ? ECX : CL;
				case OPERAND_REGISTER_DX:
					if(set_reg == BAD_REGISTER) set_reg = pOperand->size == 4 ? EDX : DL;
				case OPERAND_REGISTER_BX:
					if(set_reg == BAD_REGISTER) set_reg = pOperand->size == 4 ? EBX : BL;
				case OPERAND_REGISTER_SP:
					if(set_reg == BAD_REGISTER) set_reg = pOperand->size == 4 ? ESP : AH;
				case OPERAND_REGISTER_BP:
					if(set_reg == BAD_REGISTER) set_reg = pOperand->size == 4 ? EBP : CH;
				case OPERAND_REGISTER_SI:
					if(set_reg == BAD_REGISTER) set_reg = pOperand->size == 4 ? ESI : DH;
				case OPERAND_REGISTER_DI:
					if(set_reg == BAD_REGISTER) set_reg = pOperand->size == 4 ? EDI : BH;
				case OPERAND_EXTENDED_VAL:
				case OPERAND_GENERAL_VAL:
				case OPERAND_EXTENDED_BYTE:
				case OPERAND_GENERAL_BYTE:
					if(regs[n] == BAD_REGISTER)
						throw("Bad register");
					
					modRegRm.reg = set_reg != BAD_REGISTER ? GetRegisterID(set_reg) : GetRegisterID(reg);
					modRegRm.rm = sModRegRm::AX;
					modRegRm.mod = sModRegRm::REGISTER_INDIRECT;
					operandTemp = &opcodeDefinition->operands[n+1];

					if(operandTemp->used && set_reg == BAD_REGISTER)
					{
						if((operand->type == OPERAND_GENERAL_VAL && operandTemp->type == OPERAND_EXTENDED_VAL) ||
							(operand->type == OPERAND_GENERAL_BYTE && operandTemp->type == OPERAND_EXTENDED_BYTE) ||
							(operand->type == OPERAND_EXTENDED_VAL && operandTemp->type == OPERAND_GENERAL_VAL) ||
							(operand->type == OPERAND_EXTENDED_BYTE && operandTemp->type == OPERAND_GENERAL_BYTE))
						{
							modRegRm.rm = GetRegisterID(regs[++n]);
							modRegRm.mod = sModRegRm::REGISTER;
							tokens[n+1]->Trace();
							pToken = RegisterToken(TOKEN_HEX_BYTE, tokens[n+1]->GetString());
							pToken->SetValue(modRegRm.GetByte());
						}
						else
						{
							pToken = nullptr;
						}
					}
					
					if(set_reg != BAD_REGISTER)
					{
						if(ConvertRegisterToOperand(reg) != ConvertRegisterToOperand(set_reg))
							throw("Invalid register");
						//pToken = RegisterToken(TOKEN_HEX_BYTE, token->GetString());
						//pToken->SetValue(modRegRm.GetByte());
					}
					//else pToken = nullptr;
					break;
				}

				if(pToken)
				{
					pToken->Trace();
					size += pToken->GetSize();
				}

				n++;
			}
		}
		else
		{
			// It's that simple...
			pToken = RegisterToken(TOKEN_HEX_BYTE, tokens[0]->GetString());
			pToken->SetValue(opcode);
			pToken->Trace();
			size += pToken->GetSize();
		}
		
#undef CASE_OPCODE
#endif
	}
	
	return size;
}

eMnemonicInstruction CAssembler::GetInstruction(CToken * pToken)
{
	return GetInstruction(pToken->GetString());
}

eRegister CAssembler::GetRegister(CToken * pToken)
{
	return GetRegister(pToken->GetString());
}

eSegment CAssembler::GetSegment(CToken * pToken)
{
	return GetSegment(pToken->GetString());
}

eMnemonicInstruction CAssembler::GetInstruction(const char * szMnemonic)
{
	const sMnemonicTableEntry * entry;
	for(int i=0; i<NUM_MNEMONICS; i++)
	{
		entry = &MnemonicTable[i];
		if(!strcmp(szMnemonic, entry->mnemonic))
			return entry->instruction;
		if(*szMnemonic < *entry->mnemonic)
			break;
	}
	return BAD_INSTRUCTION;
}

eRegister CAssembler::GetRegister(const char * szRegister)
{
	const sRegisterTableEntry * entry;
	for(int i=0; i<NUM_REGISTERS; i++)
	{
		entry = &RegisterTable[i];
		if(!strcmp(szRegister, entry->szRegister))
			return entry->nRegister;
	}
	return BAD_REGISTER;
}

eSegment CAssembler::GetSegment(const char * szSegment)
{
	const sSegment * entry;
	for(int i=0; i<NUM_REGISTERS; i++)
	{
		entry = &SegmentTable[i];
		if(!strcmp(szSegment, entry->szSegment))
			return entry->nSegment;
	}
	return BAD_SEGMENT;
}

/*eOperandType CAssembler::GetRegisterOperandType(eRegister reg)
{
	switch(reg)
	{
	case EAX:	case ECX:	case EDX:	case EBX:
	case ESP:	case EBP:	case ESI:	case EDI:
	case AX:	case CX:	case DX:	case BX:
	case SP:	case BP:	case SI:	case DI:
		return OPERAND_GENERAL_VAL;
	case AL:	case CL:	case DL:	case BL:
	case AH:	case CH:	case DH:	case BH:
		return OPERAND_GENERAL_BYTE;
	}
	return BAD_OPERAND;
}*/

/*eOperandType CAssembler::ConvertRegisterToOperand(eRegister reg)
{
	switch(reg)
	{
	case EAX: case AX: case AL: case AH: return OPERAND_REGISTER_AX;
	case ECX: case CX: case CL: case CH: return OPERAND_REGISTER_CX;
	case EDX: case DX: case DL: case DH: return OPERAND_REGISTER_DX;
	case EBX: case BX: case BL: case BH: return OPERAND_REGISTER_BX;
	case ESP: case SP: return OPERAND_REGISTER_SP;
	case EBP: case BP: return OPERAND_REGISTER_BP;
	case ESI: case SI: return OPERAND_REGISTER_SI;
	case EDI: case DI: return OPERAND_REGISTER_DI;
	}
	return BAD_OPERAND;
}*/

/*sInstructionDefinition * CAssembler::GetInstructionDefinition(eMnemonicInstruction instruction)
{
	sInstructionDefinition * entry;
	for(int i=0; i<NUM_X86_OPCODES; i++)
	{
		entry = &OpcodeDefinitionTable[i];
		if(entry->instruction == instruction)
			return entry;
	}
	return nullptr;
}*/

sModRegRm::eReg CAssembler::GetRegisterID(eRegister reg)
{
	switch(reg)
	{
	default:
	case EAX: case AX: case AL: return sModRegRm::AX;
	case ECX: case CX: case CL: return sModRegRm::CX;
	case EDX: case DX: case DL: return sModRegRm::DX;
	case EBX: case BX: case BL: return sModRegRm::BX;
	case AH: case SP: case ESP: return sModRegRm::SP;
	case CH: case BP: case EBP: return sModRegRm::BP;
	case DH: case SI: case ESI: return sModRegRm::SI;
	case BH: case DI: case EDI: return sModRegRm::DI;
	}
}

/*bool CAssembler::AreOperandsCompatible(eOperandType ot1, eOperandType ot2)
{
	switch(ot1)
	{
	case OPERAND_REGISTER_AX:
	case OPERAND_REGISTER_CX:
	case OPERAND_REGISTER_DX:
	case OPERAND_REGISTER_BX:
	case OPERAND_REGISTER_SP:
	case OPERAND_REGISTER_BP:
	case OPERAND_REGISTER_SI:
	case OPERAND_REGISTER_DI:
	case OPERAND_NOMODREGRM:
		return (ot2 == OPERAND_GENERAL_BYTE || ot2 == OPERAND_GENERAL_VAL ||
				ot2 == OPERAND_EXTENDED_BYTE || ot2 == OPERAND_EXTENDED_VAL);
	case OPERAND_GENERAL_BYTE:
	case OPERAND_EXTENDED_BYTE:
		return (ot2 == OPERAND_GENERAL_BYTE || ot2 == OPERAND_EXTENDED_BYTE);
	case OPERAND_GENERAL_VAL:
	case OPERAND_EXTENDED_VAL:
		return (ot2 == OPERAND_GENERAL_VAL || ot2 == OPERAND_EXTENDED_VAL);
	case OPERAND_VALUE32:
		return (ot2 == OPERAND_VALUE32 || ot2 == OPERAND_VALUE16 || ot2 == OPERAND_VALUE8);
	case OPERAND_VALUE16:
		return (ot2 == OPERAND_VALUE16 || ot2 == OPERAND_VALUE8);
	}
	return ot1 == ot2;
}*/

int CAssembler::GetRegisterDataSize(eRegister reg)
{
	switch(reg)
	{
	default:
	case AL: case CL: case DL: case BL:
	case AH: case CH: case DH: case BH:
		return 1;
	case AX: case CX: case DX: case BX:
	case SP: case BP: case SI: case DI:
		return 2;
	case EAX: case ECX: case EDX: case EBX:
	case ESP: case EBP: case ESI: case EDI:
		return 4;
	}
	return 0;
}